package com.itheima.appserver.service;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import com.alibaba.dubbo.config.annotation.Reference;
import com.itheima.commons.model.domain.*;
import com.itheima.commons.model.vo.CountInfoVo;
import com.itheima.commons.model.vo.DistributionVo;
import com.itheima.commons.model.vo.QueryActiveRetentionVo;
import com.itheima.dubbo.interfaces.*;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
public class UserIndexService {

    @Reference
    private IndustryDistributionApi industryDistributionApi;

    @Reference
    private AgeDistributionApi ageDistributionApi;

    @Reference
    private GenderDistributionApi genderDistributionApi;

    @Reference
    private LocalDistributionApi localDistributionApi;

    @Reference
    private LocalTotalApi localTotalApi;

    @Reference
    private CountInfoApi countInfoApi;

    /**
     * 根据时间段查询
     *
     * @param start
     * @param end
     */
    public DistributionVo queryUserInfo(Long start, Long end) {
        Date startTimeDate = new Date(start);
        Date endTimeDate = new Date(end);
        DateTime beginOfDay = DateUtil.beginOfDay(startTimeDate);
        DateTime endOfDay = DateUtil.endOfDay(endTimeDate);
        String startTime = DateUtil.format(beginOfDay, "yyyy-MM-dd HH:mm:ss");
        String endTime = DateUtil.format(endOfDay, "yyyy-MM-dd HH:mm:ss");
        //查询行业分布
        List<IndustryDistribution> industryDistributionList = industryDistributionApi.query(startTime, endTime);
        //查询年龄分布
        List<AgeDistribution> ageDistributionList = ageDistributionApi.query(startTime, endTime);
        //查询性别分布
        List<GenderDistribution> genderDistributionList = genderDistributionApi.query(startTime, endTime);
        //查询地区分布
        List<LocalDistribution> localDistributionList = localDistributionApi.query(startTime, endTime);
        //地区合计
        List<LocalTotal> localTotalList = localTotalApi.query(startTime, endTime);
        //拼接页面返回对象
        DistributionVo distributionVo = new DistributionVo();
        distributionVo.setIndustryDistribution(industryDistributionList);
        distributionVo.setAgeDistribution(ageDistributionList);
        distributionVo.setGenderDistribution(genderDistributionList);
        distributionVo.setLocalDistribution(localDistributionList);
        distributionVo.setLocalTotal(localTotalList);
        return distributionVo;
    }

    /**
     * 概要统计信息
     *
     * @return
     */
    public CountInfoVo countInfo() {
        //当前时间
        Date date = new Date();
        String formatDate = DateUtil.format(date, "yyyy-MM-dd HH:mm:ss");
        //上周的时间
        DateTime lastWeekTime = DateUtil.lastWeek();
        String lastWeekTimeDate = DateUtil.format(lastWeekTime, "yyyy-MM-dd HH:mm:ss");
        //上个月的时间
        DateTime lastMonthTime = DateUtil.lastMonth();
        String lastMonthTimeDate = DateUtil.format(lastMonthTime, "yyyy-MM-dd HH:mm:ss");
        //今日开始时间
        DateTime beginOfDay = DateUtil.beginOfDay(date);
        //因为调用dubbo的时候 hutool工具包的时间类datetime会变成 把参数的时间 变成当前时间,所以要把类型转为JDK的Date类型
        Date beginOfDayDate = new Date(beginOfDay.getTime());
        //今日结束时间
        DateTime endOfDay = DateUtil.endOfDay(date);
        Date endOfDayDate = new Date(endOfDay.getTime());
        //昨天的时间对象
        DateTime yesterdayDateTime = DateUtil.offsetDay(date, -1);
        //昨天的开始时间
        DateTime yesterdayBegin = DateUtil.beginOfDay(yesterdayDateTime);
        //因为调用dubbo的时候 hutool工具包的时间类datetime会变成 把参数的时间 变成当前时间,所以要把类型转为JDK的Date类型
        Date yesterdayBeginDate = new Date(yesterdayBegin.getTime());
        //昨天的结束时间
        DateTime yesterdayEnd = DateUtil.endOfDay(yesterdayDateTime);
        //因为调用dubbo的时候 hutool工具包的时间类datetime会变成 把参数的时间 变成当前时间,所以要把类型转为JDK的Date类型
        Date yesterdayEndDate = new Date(yesterdayEnd.getTime());
        //当天时间的前天
        DateTime theDayBeforeYesterday = DateUtil.offsetDay(date, -2);
        //前天的开始时间
        DateTime theDayBeforeYesterdayBegin = DateUtil.beginOfDay(theDayBeforeYesterday);
        Date theDayBeforeYesterdayBeginDate = new Date(theDayBeforeYesterdayBegin.getTime());
        //前天的结束时间
        DateTime theDayBeforeYesterdayEnd = DateUtil.endOfDay(theDayBeforeYesterday);
        Date theDayBeforeYesterdayEndDate = new Date(theDayBeforeYesterdayEnd.getTime());
        //累计用户
        Integer cumulativeUsersCount = countInfoApi.cumulativeUsers();
        //过去30天活跃用户
        Integer activePassMonthCount = countInfoApi.activePassMonth(lastMonthTimeDate, formatDate);
        //过去7天活跃用户
        Integer activePassWeekCount = countInfoApi.activePassWeek(lastWeekTimeDate, formatDate);
        //今日新增用户
        Integer newUsersTodayCount = countInfoApi.newUsersToday(beginOfDayDate, endOfDayDate);
        //今日登录次数
        Integer loginTimesTodayCount = countInfoApi.loginTimesToday(beginOfDayDate, endOfDayDate);
        //今日活跃用户
        Integer activeUsersTodayCount = countInfoApi.activeUsersToday(beginOfDayDate, endOfDayDate);
        //昨日活跃用户
        Integer activeUsersYesterdayCount = countInfoApi.activeUsersYesterday(yesterdayBeginDate, yesterdayEndDate);


        //创建返回对象返回
        CountInfoVo countInfoVo = new CountInfoVo();

        countInfoVo.setCumulativeUsers(cumulativeUsersCount);

        countInfoVo.setActivePassMonth(activePassMonthCount);

        countInfoVo.setActivePassWeek(activePassWeekCount);

        countInfoVo.setNewUsersToday(newUsersTodayCount);
        //昨日新增用户
        Integer newUsersYesterdayCount = countInfoApi.newUsersToday(yesterdayBeginDate, yesterdayEndDate);
        //今日用户和昨日用户的差值
        Integer addEnDiv = newUsersTodayCount - newUsersYesterdayCount;
        //今日用户增长率
        countInfoVo.setNewUsersTodayRate(addEnDiv == 0 ? 0 : (calculateRate(addEnDiv, newUsersTodayCount)));
        countInfoVo.setLoginTimesToday(loginTimesTodayCount);
        //昨日登录次数
        Integer loginTimesYesterdayCount = countInfoApi.loginTimesToday(yesterdayBeginDate, yesterdayEndDate);
        //今日登录次数和昨日登录次数的差值
        Integer loginEnDiv = loginTimesTodayCount - loginTimesYesterdayCount;
        //今日登录次数涨跌率
        countInfoVo.setLoginTimesTodayRate(loginEnDiv == 0 ? 0 : (calculateRate(loginEnDiv, loginTimesTodayCount)));
        //今日活跃用户
        countInfoVo.setActiveUsersToday(activeUsersTodayCount);

        //今日活跃用户和昨日活跃用户的差值
        Integer todayActiveEnDiv = activeUsersTodayCount - activeUsersYesterdayCount;

        //今日活跃用户涨跌
        countInfoVo.setActiveUsersTodayRate(todayActiveEnDiv == 0 ? 0 : (calculateRate(todayActiveEnDiv, activeUsersTodayCount)));

        countInfoVo.setUseTimePassWeek(null);
        //昨日活跃用户
        countInfoVo.setActiveUsersYesterday(activeUsersYesterdayCount);

        //前天的活跃用户
        Integer activeUsersTheDayBeforeYesterdayCount = countInfoApi.activeUsersYesterday(theDayBeforeYesterdayBeginDate, theDayBeforeYesterdayEndDate);

        //昨日活跃用户和前日活跃用户的差值
        Integer activeUsersYesterdayEnDiv = activeUsersYesterdayCount - activeUsersTheDayBeforeYesterdayCount;

        //昨日活跃用户涨跌
        countInfoVo.setActiveUsersYesterdayRate(activeUsersYesterdayEnDiv == 0 ? 0 : (calculateRate(activeUsersYesterdayEnDiv, activeUsersYesterdayCount)));
        return countInfoVo;
    }

    /**
     * 两数相除返回百分比结果
     *
     * @param div   除数
     * @param enDiv 被除数
     */
    private Integer calculateRate(Integer enDiv, Integer div) {
        if (div == 0) {
            div = 1;
        }
        String result = NumberUtil.round(NumberUtil.div(enDiv, div), 2).toString();
        BigDecimal decimal = NumberUtil.mul(result, "100");
        Integer resultInteger = Convert.toInt(decimal);
        return resultInteger;
    }

    /**
     * 新增、活跃用户、次日留存率
     *
     * @param start
     * @param end
     * @param type
     * @return
     */
    public QueryActiveRetentionVo queryActiveRetention(Long start, Long end, Integer type) {
        //查询start end 中每天的人数
        Date startDateTime = new Date(start);
        Date endDateTime = new Date(end);
        DateTime beginOfDayTimeThisYear = DateUtil.beginOfDay(startDateTime);
        DateTime beginOfEndTimeThisYear = DateUtil.endOfDay(endDateTime);
        //String startDate = DateUtil.format(beginOfDayTimeThisYear, "yyyy-MM-dd HH:mm:ss");
        //String endDate = DateUtil.format(beginOfEndTimeThisYear, "yyyy-MM-dd HH:mm:ss");
        //根据现在时间推算出去年的时间
        DateTime dateTimeStart = DateUtil.offsetMonth(startDateTime, -12);
        DateTime beginOfDayTime = DateUtil.beginOfDay(dateTimeStart);
        DateTime dateTimeEnd = DateUtil.offsetMonth(endDateTime, -12);
        DateTime dateTimeEndTime = DateUtil.endOfDay(dateTimeEnd);
        //String LastYearStartDate = DateUtil.format(beginOfDayTime, "yyyy-MM-dd HH:mm:ss");
        //String LastYearEndDate = DateUtil.format(dateTimeEndTime, "yyyy-MM-dd HH:mm:ss");
        if (type == 101) {
            List<thisYear> thisYearList = new ArrayList<>();
            List<lastYear> lastYearList = new ArrayList<>();
            long thisYearDays = DateUtil.between(startDateTime, endDateTime, DateUnit.DAY);
            for (int i = 0; i <thisYearDays; i++) {
                String beginOfDay = DateUtil.beginOfDay(startDateTime).toString();
                String dateTime = DateUtil.endOfDay(startDateTime).toString();
                Integer amount = countInfoApi.queryAddCount(beginOfDay, dateTime);
                int title = startDateTime.getDate();
                thisYear thisYear = new thisYear();
                thisYear.setTitle(Convert.toStr(title));
                thisYear.setAmount(amount);
                thisYearList.add(thisYear);
                startDateTime=DateUtil.offsetDay(startDateTime,1);
            }
            long lastYearDays = DateUtil.between(dateTimeStart, dateTimeEndTime, DateUnit.DAY);
            for (int i = 0; i <lastYearDays; i++) {
                String beginOfDay = DateUtil.beginOfDay(dateTimeStart).toString();
                String dateTime = DateUtil.endOfDay(dateTimeStart).toString();
                Integer amount = countInfoApi.queryAddCount(beginOfDay, dateTime);
                int title = startDateTime.getDate();
                lastYear lastYear = new lastYear();
                lastYear.setTitle(Convert.toStr(title));
                lastYear.setAmount(amount);
                lastYearList.add(lastYear);
                dateTimeStart=DateUtil.offsetDay(dateTimeStart,1);
            }
             QueryActiveRetentionVo queryActiveRetentionVo = new QueryActiveRetentionVo();
             queryActiveRetentionVo.setThisYear(thisYearList);
             queryActiveRetentionVo.setLastYear(lastYearList);
                return queryActiveRetentionVo;
        } else if (type == 102) {
            List<thisYear> thisYearList = new ArrayList<>();
            List<lastYear> lastYearList = new ArrayList<>();
            /*List<thisYear> thisYearList = countInfoApi.queryEveryActiveThisYear(startDate, endDate);
            List<lastYear> lastYearList = countInfoApi.queryEveryActiveLastYear(LastYearStartDate, LastYearEndDate);
            QueryActiveRetentionVo queryActiveRetentionVo = new QueryActiveRetentionVo();
            queryActiveRetentionVo.setThisYear(thisYearList);
            queryActiveRetentionVo.setLastYear(lastYearList);
            return queryActiveRetentionVo;*/
            long thisYearDays = DateUtil.between(startDateTime, endDateTime, DateUnit.DAY);
            for (int i = 0; i <thisYearDays; i++) {
                String beginOfDay = DateUtil.beginOfDay(startDateTime).toString();
                String dateTime = DateUtil.endOfDay(startDateTime).toString();
                Integer amount = countInfoApi.queryActiveCount(beginOfDay, dateTime);
                int title = startDateTime.getDate();
                thisYear thisYear = new thisYear();
                thisYear.setTitle(Convert.toStr(title));
                thisYear.setAmount(amount);
                thisYearList.add(thisYear);
                startDateTime = DateUtil.offsetDay(startDateTime, 1);
            }
            long lastYearDays = DateUtil.between(dateTimeStart, dateTimeEndTime, DateUnit.DAY);
            for (int i = 0; i <lastYearDays; i++) {
                String beginOfDay = DateUtil.beginOfDay(dateTimeStart).toString();
                String dateTime = DateUtil.endOfDay(dateTimeStart).toString();
                Integer amount = countInfoApi.queryActiveCount(beginOfDay, dateTime);
                int title = startDateTime.getDate();
                lastYear lastYear = new lastYear();
                lastYear.setTitle(Convert.toStr(title));
                lastYear.setAmount(amount);
                lastYearList.add(lastYear);
                dateTimeStart=DateUtil.offsetDay(dateTimeStart,1);
            }
            QueryActiveRetentionVo queryActiveRetentionVo = new QueryActiveRetentionVo();
            queryActiveRetentionVo.setThisYear(thisYearList);
            queryActiveRetentionVo.setLastYear(lastYearList);
            return queryActiveRetentionVo;
        } else {
            //传进来两个时间的时间间隔
            long betweenDays = DateUtil.between(startDateTime, endDateTime, DateUnit.DAY);
            List<thisYear> thisYearList = new ArrayList<>();
            List<lastYear> lastYearList = new ArrayList<>();
            for (int i = 0; i < betweenDays; i++) {
                //开始时间当天的起始时间和结束时间
                DateTime beginOfDay = DateUtil.beginOfDay(startDateTime);
                DateTime endOfDay = DateUtil.endOfDay(endDateTime);
                //把当天的格式改成Date格式
                Date beginOfDayDate = dateTimeToDate(beginOfDay);
                Date endOfDayDate = dateTimeToDate(endOfDay);
                //开始时间的前一天
                DateTime offStartDay = DateUtil.offsetDay(startDateTime, -1);
                //传进来的开始时间的前一天的时间的开始时间
                DateTime offStartDayBegin = DateUtil.beginOfDay(offStartDay);
                //把昨天的时间从DateTime转化成Date
                Date yesterdayDateStart = dateTimeToDate(offStartDayBegin);
                //传进来的开始时间的前一天的时间的结束时间
                DateTime offStartDayEnd = DateUtil.endOfDay(offStartDay);
                //把昨天的时间从DateTime转化成Date
                Date yesterdayDateEnd = dateTimeToDate(offStartDayEnd);
                //查询当前时间前一天的新增用户
                Integer newlyCount = countInfoApi.newUsersToday(yesterdayDateStart, yesterdayDateEnd);
                //查询昨天注册今天登录的人数
                Integer withYesterdayNewlyCount = countInfoApi.queryActiveWithYesterdayNewly(beginOfDayDate, endOfDayDate, yesterdayDateStart, yesterdayDateEnd);
                thisYear thisYear = new thisYear();
                thisYear.setTitle(startDateTime.getDate() + "");
                thisYear.setAmount(withYesterdayNewlyCount == 0 ? 0 : (calculateRate(withYesterdayNewlyCount, newlyCount)));
                thisYearList.add(thisYear);
                lastYear lastYear = new lastYear();
                lastYear.setTitle(startDateTime.getDate()+"");
                lastYear.setAmount(withYesterdayNewlyCount == 0 ? 0 : (calculateRate(withYesterdayNewlyCount, newlyCount)));
                lastYearList.add(lastYear);
                startDateTime = DateUtil.offsetDay(startDateTime, 1);
            }
            QueryActiveRetentionVo queryActiveRetentionVo = new QueryActiveRetentionVo();
            queryActiveRetentionVo.setThisYear(thisYearList);
            queryActiveRetentionVo.setLastYear(lastYearList);
            return queryActiveRetentionVo;
        }
    }

    /**
     * 把一个DateTime 格式的时间对象转成一个Date格式
     *
     * @param dateTime
     * @return
     */
    public Date dateTimeToDate(DateTime dateTime) {
        return new Date(dateTime.getTime());
    }
}
